package com.jy.oms.framework.asyn.task.checker;

import com.jy.oms.framework.asyn.task.alarm.AlarmMessage;
import com.jy.oms.framework.asyn.task.alarm.AlarmMessageFacade;
import com.jy.oms.framework.asyn.task.cluster.config.ITaskConfigChangeListener;
import com.jy.oms.framework.asyn.task.cluster.config.ITaskConfigService;
import com.jy.oms.framework.asyn.task.constants.ConfigConstants;
import com.jy.oms.framework.asyn.task.exception.TaskConfigException;
import com.jy.oms.framework.asyn.task.handler.ITaskHandlerProcessor;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;

/**
 * 任务在指定时间规则下运行配置
 *
 * @author liuquan
 */
@Service
public class ExecuteTimeRulesConfig implements ITaskHandlerProcessor {
    private static Logger logger = LoggerFactory.getLogger(ExecuteTimeRulesConfig.class);
    @Autowired
    private ITaskConfigService configService;
    private DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss");
    private Map<String, ExecuteTimeRule> executorTimeRule = new HashMap<>();
    private volatile boolean isAlarmOnConfigChange;

    @Override
    public void processAfterTaskHandlerInitialization() {
        //监听配置变化
        configService.addTaskConfigChangeListener(new ITaskConfigChangeListener() {
            @Override
            public String getConfigKey() {
                return ConfigConstants.EXECUTOR_TASK_TIME_RULE;
            }

            @Override
            public void onConfigChange(String configKey, String config) {
                executorTimeRule = parseRule(config);

                //初始化时不告警
                if (isAlarmOnConfigChange) {
                    alarm(executorTimeRule);
                }else{
                    isAlarmOnConfigChange = true;
                }
            }
        });
    }

    private Map<String, ExecuteTimeRule> parseRule(String rules) {
        Map<String, ExecuteTimeRule> ruleMap = new HashMap<>();
        if (StringUtils.isBlank(rules)) {
            return ruleMap;
        }

        try {
            String[] ruleGroups = rules.split("[|]");
            for (String ruleGroup : ruleGroups) {
                String[] detailRules = ruleGroup.split(",");
                if (detailRules.length != 2) {
                    throw new TaskConfigException("解析任务时间规则报错, rule: " + ruleGroup);
                }

                String taskCode = detailRules[0];
                String[] times = detailRules[1].split("-");
                if (times.length != 2) {
                    throw new TaskConfigException("解析任务时间规则报错, rule: " + ruleGroup);
                }

                ExecuteTimeRule rule = new ExecuteTimeRule();
                rule.startTime = LocalTime.parse(times[0], dateTimeFormatter);
                rule.endTime = LocalTime.parse(times[1], dateTimeFormatter);
                ruleMap.put(taskCode, rule);
            }
        } catch (Exception e) {
            logger.error("解析规则报错", e);
        }
        return ruleMap;
    }

    private void alarm(Map<String, ExecuteTimeRule> executorTimeRule) {
        if (MapUtils.isEmpty(executorTimeRule)) {
            return;
        }

        AlarmMessage alarmMessage = AlarmMessage.create().title("任务执行时间规则");
        for (Map.Entry<String, ExecuteTimeRule> entry : executorTimeRule.entrySet()) {
            String rule = dateTimeFormatter.format(entry.getValue().startTime) + " - " + dateTimeFormatter.format(entry.getValue().endTime);
            alarmMessage.add(entry.getKey(), rule);
        }

        AlarmMessageFacade.getInstance().alarm(alarmMessage);
    }

    public ExecuteTimeRule getTaskExecuteTimeRule(String taskCode){
        return this.executorTimeRule.get(taskCode);
    }

    public class ExecuteTimeRule {
        private LocalTime startTime;
        private LocalTime endTime;

        public LocalTime getStartTime() {
            return startTime;
        }

        public void setStartTime(LocalTime startTime) {
            this.startTime = startTime;
        }

        public LocalTime getEndTime() {
            return endTime;
        }

        public void setEndTime(LocalTime endTime) {
            this.endTime = endTime;
        }
    }
}
